#include "FileWriter.h"
#include "LittleEndian.h"
#include "WONFile.h"

using namespace WONAPI;

///////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
FileWriter::FileWriter()
{
	mFile = NULL;
}

///////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
FileWriter::~FileWriter()
{
	Close();
}

///////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
bool FileWriter::Open(const char *theFilePath, bool openIfReadOnly)
{
	Close();
	if(theFilePath[0]=='\0') // MS fopen.c asserts if theFilePath is empty
		return false;

	mFile = fopen(theFilePath,"wb");
	if(mFile==NULL && openIfReadOnly)
	{
		WONFile aFile(theFilePath);
		aFile.SetReadOnly(false);
		mFile = fopen(theFilePath,"wb");
	}
	return mFile!=NULL;
}

///////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
void FileWriter::Close()
{
	if(mFile!=NULL)
	{
		fclose(mFile);
		mFile = NULL;
	}
}


///////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
unsigned long FileWriter::pos()
{
	if(mFile!=NULL)
		return ftell(mFile);
	else
		return 0;
}

///////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
void FileWriter::SetPos(unsigned long thePos)
{
	if(mFile!=NULL)
	{
		if(fseek(mFile,thePos,SEEK_SET)!=0)
			throw FileWriterException("Attempt to setpos past end of file.");
	}
}


///////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
void FileWriter::WriteBytes(const void *theBuf, unsigned long theNumBytes)
{
	if(mFile==NULL)
		throw FileWriterException("NULL File.");

	if(fwrite(theBuf,1,theNumBytes,mFile)!=theNumBytes)
		throw FileWriterException("fwrite failed (disk full)");
}

///////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
void FileWriter::WriteByte(unsigned char theByte)
{
	WriteBytes(&theByte,1);
}

///////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
void FileWriter::WriteShort(unsigned short theShort)
{
	theShort = ShortToLittleEndian(theShort);
	WriteBytes(&theShort,2);
}

///////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
void FileWriter::WriteLong(unsigned long theLong)
{
	theLong = LongToLittleEndian(theLong);
	WriteBytes(&theLong,4);
}

///////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
void FileWriter::WriteLength(unsigned long theLen, unsigned char theLengthFieldSize)
{
	switch(theLengthFieldSize)
	{
		case 1: WriteByte(theLen); break;
		case 2: WriteShort(theLen); break;
		case 4: WriteLong(theLen); break;
		default: break;
	}
}

///////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
void FileWriter::WriteRawString(const std::string &theStr)
{
	WriteBytes(theStr.data(),theStr.length());
}

///////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
void FileWriter::WriteRawWString(const std::wstring &theWStr)
{
	if(IsLittleEndian() && sizeof(wchar_t)==2)
		WriteBytes(theWStr.data(),theWStr.length()*2);
	else
	{
		for(int i=0; i<theWStr.length(); i++)
			WriteShort(theWStr[i]);
	}
}

///////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
void FileWriter::WriteString(const std::string &theStr, unsigned char theLengthFieldSize)
{
	WriteLength(theStr.length(),theLengthFieldSize);
	WriteRawString(theStr);
}

///////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
void FileWriter::WriteWString(const std::wstring &theWStr, unsigned char theLengthFieldSize)
{
	WriteLength(theWStr.length(),theLengthFieldSize);
	WriteRawWString(theWStr);
}
